﻿using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Volo.Abp.Domain;
using SqlSugar;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Volo.Abp.Data;
using System.Threading;
using Volo.Abp.Domain.Entities;
using System.Threading.Tasks;
using Volo.Abp.SqlSugarCore.DependencyInjection;

namespace Volo.Abp.SqlSugarCore.SqlSugarFactory
{
    public class DefaultSqlSugarClientFactory : ISqlSugarClientFactory
    {
        public ILogger _logger { get; private set; }

        AbpDbConnectionOptions _dbConfig;
        SqlSugarClientConfigSetting _sugarClientConfigSetting;
        SqlSugarSerializeService _sqlSugarSerializeService;
        public DefaultSqlSugarClientFactory(ILoggerFactory loggerFactory
            , IOptions<AbpDbConnectionOptions> options
            , IOptions<SqlSugarClientConfigSetting> sugarClientConfigSettingOpt
            , SqlSugarSerializeService sqlSugarSerializeService)
        {
            _logger = loggerFactory.CreateLogger<DefaultSqlSugarClientFactory>();
            _dbConfig = options.Value;
            _sugarClientConfigSetting = sugarClientConfigSettingOpt.Value;
            _sqlSugarSerializeService = sqlSugarSerializeService;
        }


        private ISqlSugarClient _context;

        private static object lockObj = new object();

        public ISqlSugarClient CreateClient()
        {
            if (_context != null)
            {
                return _context;
            }

            //同一个线程内拿到的数据库连接是同一个
            lock (lockObj)
            {
                ISqlSugarClient context = null;
                //自定义扩展方法
                var expMethods = new List<SqlFuncExternal>();
                expMethods.Add(new SqlFuncExternal()
                {
                    UniqueMethodName = "GroupConcat",
                    MethodValue = (expInfo, dType, expContext) =>
                    {
                        if (dType == SqlSugar.DbType.MySql)
                            return string.Format("GROUP_CONCAT({0})", expInfo.Args[0].MemberName);
                        else
                            throw new Exception("未实现GroupConcat方法");
                    }
                });


                SqlSugar.DbType dbType = GetDbType(_dbConfig.ConnectionStrings.ContainsKey("Provide") ? _dbConfig.ConnectionStrings["Provide"] : "");

                context = new SqlSugarClient(new ConnectionConfig()
                {
                    ConnectionString = _dbConfig.ConnectionStrings.Default,
                    DbType = dbType,
                    InitKeyType = InitKeyType.Attribute,//从特性读取主键和自增列信息
                    IsAutoCloseConnection = true,//开启自动释放模式
                    ConfigureExternalServices = new ConfigureExternalServices()
                    {
                        EntityService = (t, column) =>
                        {
                            if (column.PropertyName.ToLower() == "id") //是id的设为主键
                            {
                                column.IsPrimarykey = true;
                                if (column.PropertyInfo.PropertyType == typeof(int)) //是id并且是int的是自增
                                {
                                    column.IsIdentity = true;
                                }
                            }
                            if (column.PropertyName.ToLower() == "creationname") //´´½¨ÈËÃû³Æ
                            {
                                column.Length = 64;
                                column.IsNullable = false;
                                column.DefaultValue = "";
                            }
                            var columnName = column.PropertyName.ToLower();
                            if (columnName == "deleterid" || columnName == "deletiontime" || columnName == "lastmodificationtime" || columnName == "lastmodifierid") //
                            {
                                column.IsNullable = true;
                            }
                            if (column.PropertyName.ToLower() == "CreatorId") //´´½¨ÈËÃû³Æ
                            {
                                column.Length = 36;
                                column.IsNullable = false;
                                column.DefaultValue = Guid.Empty.ToString();
                            }
                            if (column.PropertyName.ToLower() == "CreationTime") //´´½¨ÈËÃû³Æ
                            {
                                column.IsNullable = false;
                                column.DefaultValue = DateTime.Now.ToString();
                            }
                            if (column.PropertyInfo.PropertyType == typeof(ExtraPropertyDictionary))
                            {
                                column.IsJson = true;
                                column.DefaultValue = "";
                            }
                        },
                        SerializeService = _sqlSugarSerializeService,

                        SqlFuncServices = expMethods//set ext method
                    }
                });

                //执行之前
                context.Aop.OnLogExecuting = (sql, pars) =>
                {
                    _logger.LogDebug("sql=" + sql + @"\r\n参数为：" +
                                    context.Utilities.SerializeObject((pars).ToDictionary(it => it.ParameterName,
                                        it => it.Value)));

                };
                //执行完成
                context.Aop.OnLogExecuted = (sql, pars) =>
                {
                    _logger.LogDebug("执行花费时间：" + context.Ado.SqlExecutionTime.TotalMilliseconds + "mm");
                    //
                    if (context.Ado.SqlExecutionTime.TotalMilliseconds > 1000)
                    {

                    }
                };
                //发生异常
                context.Aop.OnError = (exp) =>
                {
                    _logger.LogError("sql=" + exp.Sql + @"\r\n参数为：" +
                                    context.Utilities.SerializeObject(((SugarParameter[])exp.Parametres).ToDictionary(it => it.ParameterName,
                                        it => it.Value)));

                    _logger.LogError("sql执行发送异常：", exp.InnerException);
                };

                _context = context;
            }

            ///执行外面配置项
            _sugarClientConfigSetting.ExecSugarClientConfigAction(_context);


            return _context;
        }


        private DbType GetDbType(string dbtype)
        {
            DbType dbType = DbType.MySql;
            switch (dbtype)
            {
                case "sqlserver":
                    dbType = SqlSugar.DbType.SqlServer;
                    break;
                case "mysql":
                    dbType = SqlSugar.DbType.MySql;
                    break;
                case "oracle":
                    dbType = SqlSugar.DbType.Oracle;
                    break;
                case "sqlite":
                    dbType = SqlSugar.DbType.Sqlite;
                    break;
                case "postgresql":
                    dbType = SqlSugar.DbType.PostgreSQL;
                    break;
                default:
                    throw new ApplicationException("不支持的数据库");
            }

            return dbType;
        }
    }
}
